package cz.vutbr.fit.dnacompress.encoding;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.biojava.utils.ParserException;

import cz.vutbr.fit.dnacompress.events.AlignEvent;

public class HuffmanCoder extends AbstractCoder {

	public HuffmanCoder(String countTableFileName) throws IOException, ParserException {
		
		setCountTables( countTableFileName);
		this.coderID = 4;
	}

	@Override
	public List<AlignEvent> decode(InputStream is) throws IOException, ParserException {
		
		// cteni input streamu do bufferu
		ByteBuffer byteBuffer = ByteBuffer.allocate( 1000);
		int r, byteCount = 0;
		while((r = is.read()) != -1) {
			byteBuffer.put((byte) r);
			byteCount++;
		}
		byteBuffer.rewind();
		byte tmpData[] = byteBuffer.array();
		
		// ziskani rice dat uchovane v poli items
		RiceCode rc = new RiceCode( tmpData);
		int [] items = rc.getItems();
		// delka ziskanych rice dat
		int riceLength = (rc.getNumBits() / 8) + 7;
		
		// delka huffman dat
		int dataLength = byteCount - riceLength;
		// oseknuti rice dat -> zbydou jen huffman datas
		byte datain[] = new byte[dataLength];
		System.arraycopy( tmpData, riceLength, datain, 0, datain.length);
		// dekodovani huffmana
		HuffmanDNA hd = new HuffmanDNA( countTableDecode);
		byte huffDataout[] = hd.uncompress(datain);
		
		// vytvoreni eventu
		List<AlignEvent> events = new ArrayList<AlignEvent>();
		for(int i=0;i<items.length;i++) {
			
			AlignEvent event = AlignEvent.getClassWithData( countTableDecode.get( (int) huffDataout[i]));
			event.setPosition( items[i]);
			events.add( event);
		}
		
		return events;
	}

	@Override
	public byte[] encode(List<AlignEvent> events) {
		
		// delka eventu
		int dataLength = events.size();
		
		// koder pro pozice
		RiceCode rc = new RiceCode( 8);	
		
		// buffer pro vztupni data huffmana
		ByteBuffer bf = ByteBuffer.allocate( dataLength);
		
		// pro kazdy event
		for( Iterator<AlignEvent> i = events.iterator(); i.hasNext();) {
			
			AlignEvent event = i.next();
			// ziskani offsetu v tabulce poctu pro dany event
			Integer variantTableOffset = countTableEncode.get( event.getCountID());
			// vlozeni offsetu do bufferu
			bf.put( variantTableOffset.byteValue());
			
			// pozice eventu
			int position = event.getPosition();
			// vlozeni pozice do rice coderu
			rc.addItem( position);
		}
		bf.rewind();
		
		// zakodovani huffmana
		HuffmanDNA hd = new HuffmanDNA( countTableDecode);
		byte huffDataout[] = hd.compress(bf.array());
		
		ByteBuffer bfOut = ByteBuffer.allocate( rc.getBits().length + huffDataout.length);
		bfOut.put( rc.getBits());
		bfOut.put( huffDataout);
		bfOut.rewind();
		
		return bfOut.array();
	}
	
	public String toString() {
		return "Huffman coder";
	}

}
